--[[
  10.1.14.234:30045 esb (基于HTTP协议,注意传输的是二进制形式的XML)
]]
require("apm_core");
require("ApmXml");

local G_DEBUG = true;

if G_DEBUG == false then
    function logDebug(fmt,...) end
    function logInfo(fmt,...) end
    function logWarn(fmt,...) end
    function logError(fmt,...) end
    function logFatal(fmt,...) end
end

local t_xml_tree;
local s_brc
local s_seq_no
local s_teller
local s_tran_code
local s_type_name
local s_channel_id
local s_rspcode
local s_rspmsg
local s_message_req
local s_message_resp

local function parseIp(ip)
    local _, _, value = string.find(ip, "(%d+.%d+)$");
    return value == nil and "" or value
end

--- 协议判断
-- return
-- true; false
local function protocol_detect(s_payload)
    if s_payload == nil then return false end;

    t_xml_tree = ApmXml.load(s_payload);

    return ApmXml.getValue(t_xml_tree, "/service") ~= nil;
end

local arr_service_code = {};
--arr_service_code["11002000005"] = "业务名称-测试";
--arr_service_code["11003000001"] = "对公客户信息查询";

local arr_channel_id = {}
arr_channel_id["00"] = "主机"
arr_channel_id["01"] = "银联中心atm"
arr_channel_id["02"] = "银联中心cdm"
arr_channel_id["03"] = "银联中心pos"
arr_channel_id["04"] = "银联中心crs存取款一体机"
arr_channel_id["05"] = "银联中心自助查询终端"
arr_channel_id["06"] = "银联中心柜台"
arr_channel_id["07"] = "银联中心网上银行"
arr_channel_id["08"] = "银联中心手机银行"
arr_channel_id["09"] = "银联中心电话银行"
arr_channel_id["10"] = "银联中心圈存圈提设备"
arr_channel_id["11"] = "银联中心移动pos"
arr_channel_id["12"] = "本行柜台"
arr_channel_id["13"] = "本行atm"
arr_channel_id["14"] = "本行pos"
arr_channel_id["15"] = "本行cdm"
arr_channel_id["16"] = "本行电话银行"
arr_channel_id["17"] = "本行网上银行"
arr_channel_id["18"] = "本行手机银行"
arr_channel_id["19"] = "本行自助查询终端"
arr_channel_id["20"] = "本行呼叫中心"
arr_channel_id["21"] = "本行crs存取款一体机"
arr_channel_id["22"] = "银联商务pos"
arr_channel_id["23"] = "建行atm"
arr_channel_id["24"] = "建行pos设备"
arr_channel_id["25"] = "华夏银行atm"
arr_channel_id["26"] = "香港atm"
arr_channel_id["27"] = "澳门atm"
arr_channel_id["28"] = "支付系统"
arr_channel_id["29"] = "本行柜面通"
arr_channel_id["30"] = "国际结算"
arr_channel_id["31"] = "银联数据（贷记卡）"
arr_channel_id["32"] = "香港pos"
arr_channel_id["33"] = "澳门pos"
arr_channel_id["34"] = "欧洲atm"
arr_channel_id["35"] = "欧洲pos"
arr_channel_id["36"] = "新加坡atm"
arr_channel_id["37"] = "新加坡pos"
arr_channel_id["38"] = "泰国atm"
arr_channel_id["39"] = "泰国pos"
arr_channel_id["40"] = "韩国atm"
arr_channel_id["41"] = "韩国pos"
arr_channel_id["42"] = "银联公共服务平台"
arr_channel_id["43"] = "美国atm"
arr_channel_id["44"] = "德国atm"
arr_channel_id["45"] = "法国atm"
arr_channel_id["46"] = "日本atm"
arr_channel_id["47"] = "印度尼西亚atm"
arr_channel_id["48"] = "菲律宾atm"
arr_channel_id["49"] = "越南atm"
arr_channel_id["50"] = "老挝atm"
arr_channel_id["51"] = "美国pos"
arr_channel_id["52"] = "德国pos"
arr_channel_id["53"] = "法国pos"
arr_channel_id["54"] = "日本pos"
arr_channel_id["55"] = "印度尼西亚pos"
arr_channel_id["56"] = "菲律宾pos"
arr_channel_id["57"] = "越南pos"
arr_channel_id["58"] = "老挝pos"
arr_channel_id["64"] = "本行无线pos"
arr_channel_id["65"] = "本行固话pos"
arr_channel_id["66"] = "本行mis"
arr_channel_id["72"] = "银联中心公共服务平台"
arr_channel_id["73"] = "银联中心农民工银行卡特色服务"
arr_channel_id["74"] = "银联中心商户系统"
arr_channel_id["75"] = "银联中心第三方机构系统（目前主要是渠道接入机构）"
arr_channel_id["76"] = "银联中心数字机顶盒"
arr_channel_id["77"] = "银联中心II型固定电话"
arr_channel_id["78"] = "银联中心保留使用"
arr_channel_id["79"] = "银联中心保留使用"
arr_channel_id["80"] = "银联中心批量文件处理系统"
arr_channel_id["81"] = "银联中心Reserved for use"
arr_channel_id["82"] = "银联中心音频刷卡支付终端（VI-POS）"
arr_channel_id["97"] = "中间业务前台"
arr_channel_id["98"] = "中间业务第三方"
arr_channel_id["99"] = "其他"
arr_channel_id["QS"] = "卡清算综合平台"
arr_channel_id["BB"] = "第三方存管业务系统"
arr_channel_id["CB"] = "城商行联盟"
arr_channel_id["T1"] = "电信一卡通"
arr_channel_id["MP"] = "小额支付系统"
arr_channel_id["IM"] = "影像系统"
arr_channel_id["BD"] = "债券"
arr_channel_id["ZL"] = "银联分公司pos转发"
arr_channel_id["A0"] = "其他"


--- 解析请求
-- return
-- true: 解析成功; false: 解析失败
local function trade_parse_request(ApmData)

    -- 流水号
    s_seq_no = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"CONSUMER_SEQ_NO\"]/field/text()");
--    ApmData.replaceField("transaction.seq_no", s_seq_no == nil and "" or string.trim(s_seq_no))
    ApmData.replaceField("transaction.code", s_seq_no == nil and "" or string.trim(s_seq_no))

    -- 机构号
    s_brc = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"BRANCH_ID\"]/field/text()");
    ApmData.replaceField("transaction.branch_code", s_brc == nil and "" or string.trim(s_brc))

    -- 柜员号
    s_teller = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"TELLER_NO\"]/field/text()");
    ApmData.replaceField("transaction.teller_code", s_teller == nil and "" or string.trim(s_teller))

    -- 交易名
    s_type_name = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"SERVICE_CODE\"]/field/text()");
    ApmData.replaceField("transaction.type_code", s_type_name == nil and "未知" or string.trim(s_type_name))
    ApmData.replaceField("transaction.type_name", s_type_name == nil and "未知" or string.trim(s_type_name))
--    ApmData.replaceField("transaction.title", s_type_name == nil and "未知" or string.trim(s_type_name))
--    s_text = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"SERVICE_CODE\"]/field/text()");
--    if s_text ~= nil then
--        s_text = string.trim(s_text);
--        local s_type_name = arr_service_code[s_text];
--        if s_type_name == nil then s_type_name = s_text end
--        ApmData.replaceField("transaction.type_code", s_text);
--        ApmData.replaceField("transaction.type_name", s_type_name);
--        logInfo("SERVICE_CODE:[%s] type_code:[%s] type_name:[%s]", s_text, s_text, s_type_name);
--    end

    -- 服务场景
--    s_text = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"SERVICE_SCENE\"]/field/text()");
--    if s_text ~= nil then
--        s_text = string.trim(s_text);
        --        logInfo("SERVICE_SCENE:[%s]", s_text);
--    end

    s_channel_id = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"SOURCE_TYPE\"]/field/text()");
    if s_channel_id == nil then
        s_channel_id = "未知"
    else
        local s_channel_id_in_arr = arr_channel_id[s_channel_id];
        if s_channel_id_in_arr == nil then
        else
            s_channel_id = s_channel_id_in_arr
        end
    end
    ApmData.replaceField("transaction.channel_code", s_channel_id)
    ApmData.replaceField("transaction.channel_name", s_channel_id)

    return true;
end

--- 解析响应
-- return
-- true: 解析成功; false: 解析失败
local function trade_parse_response(ApmData)

    -- 交易状态
--    s_text = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"RET_STATUS\"]/field/text()");
--    if s_text ~= nil then
--        s_text = string.trim(s_text);
--        s_text = s_text == "S" and 0 or 1;
--        ApmData.replaceField("response.code", s_text);
--        logInfo("RET_STATUS:[%d]", s_text);
--    end

    -- 交易返回代码
    s_rspcode = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"RET\"]/array/struct[1]/data[@name=\"RET_CODE\"]/field/text()");
    if s_rspcode ~= nil then
        s_rspcode = string.trim(s_rspcode);
        ApmData.replaceField("response.code_string", s_rspcode);
    end

    -- 交易返回信息
    s_rspmsg = ApmXml.getValue(t_xml_tree, "/service/sys-header/data[@name=\"SYS_HEAD\"]/struct/data[@name=\"RET\"]/array/struct[1]/data[@name=\"RET_MSG\"]/field/text()");
    if s_rspmsg ~= nil then
        s_rspmsg = string.trim(s_rspmsg);
        ApmData.replaceField("response.error_message", s_rspmsg);
    end

    return true;
end

--- main
function post_analysis()
    local ApmData = require("ApmData");
    if ApmData.getL7Proto() ~= 80 then return end

    local s_em_type = ApmData.getMsgType();
    if s_em_type == nil then return end

    -- 设置交易渠道
--    local s_src_ip = ApmData.getSrcIp();
--    if s_src_ip ~= nil then
--        ApmData.replaceField("transaction.channel_name", s_src_ip);
--        ApmData.replaceField("transaction.channel_code", s_src_ip);
--    end

    local s_content_type, s_http_body;

    if s_em_type == 0 then -- 请求
        s_content_type = ApmData.getField("request.http.header.content-type", 1);
        s_http_body = ApmData.getField("request.http.body.1", 1);
        if s_content_type ~= nil and s_http_body ~= nil
        then
            s_http_body = string.trim(s_http_body);
            if protocol_detect(s_http_body) then
                trade_parse_request(ApmData);
            end
        end
    elseif s_em_type == 1 then -- 响应
        s_content_type = ApmData.getField("request.http.header.content-type", 1);
        s_http_body = ApmData.getField("request.http.body.1", 1);
        if s_content_type ~= nil and s_http_body ~= nil then
            s_message_req = string.trim(s_http_body);
            if protocol_detect(s_message_req) then
                trade_parse_request(ApmData);
            end
        end

        s_http_body = ApmData.getField("response.http.body.1", 1);
        if s_http_body ~= nil then
            s_message_resp = string.trim(s_http_body);
            if protocol_detect(s_message_resp) then
                trade_parse_response(ApmData);
            end
        end

        if s_rspcode ~= nil then
            ApmData.delFields("response.code")
        end

        logInfo("信贷ESB(%s->%s) 流水号:%s|机构号:%s|柜员号:%s|交易号:%s|交易名:%s|交易渠道:%s|返回码:%s|%s",
            parseIp(ApmData.getSrcIp()),
            parseIp(ApmData.getDstIp()),
            s_seq_no,
            s_brc,
            s_teller,
            s_tran_code == nil and "esb是没有交易码的" or s_tran_code,
            s_type_name,
            s_channel_id,
            s_rspcode,
            s_rspmsg == nil and "" or s_rspmsg)

        if s_seq_no == nil or
                s_brc == nil or
                s_type_name == nil or
                s_channel_id == nil or
                s_rspcode == nil then
            logError("信贷ESB:REQ:[%s]\nRESP:[%s]", s_message_req, s_message_resp)
        end
    end

    return;
end
